package com.macro.mall.portal.util;


import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.UnknownHostException;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.Objects;
import java.util.Set;

public class MyHttpUtil {

    private static final Logger logger = LoggerFactory.getLogger(MyHttpUtil.class);

    private static final RestTemplate client = new RestTemplate();


    /**
     * 发送POST请求
     *
     * @param url        请求URL
     * @param headerJson 请求头的json数据
     * @param queryJson  请求query参数的json数据
     * @param bodyStr    请求body的字符串
     * @return 返回响应body的字符串内容
     * @throws Exception
     */
    public static String sendPOST(String url, JSONObject headerJson, JSONObject queryJson, String bodyStr) {
        long start = System.currentTimeMillis();

        client.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

        if (queryJson != null) {
            url = url.contains("?") ? url : url + "?";

            StringBuilder urlBuffer = new StringBuilder(url);
            Set<String> querySet = queryJson.keySet();
            for (String queryName : querySet) {
                urlBuffer.append("&").append(queryName).append("=").append(queryJson.get(queryName).toString());
            }

            url = urlBuffer.toString();
        }

        HttpHeaders headers = new HttpHeaders();
        if (headerJson != null) {
            Set<String> headerKeys = headerJson.keySet();
            for (String headerName : headerKeys) {
                headers.set(headerName, headerJson.getString(headerName));
            }
        }
        HttpEntity<String> request = new HttpEntity<>(bodyStr, headers);

        ResponseEntity<String> responseEntity = client.exchange(url, HttpMethod.POST, request, String.class);

        String resBodyStr = responseEntity.getBody();
        String resBodyStrLine = "";
        if (resBodyStr != null) {
            // 将响应整理为一行，方便记录日志
            resBodyStrLine = resBodyStr.replaceAll("\n", "");
        }

        long costTime = System.currentTimeMillis() - start;

        logger.info("[MyHttpUtil] - <sendPOST> --- URL：{}，HEADER-JSON：{}，REQUEST-BODY：{}，RESPONSE-BODY：{}，COST-TIME：{}ms", url, headerJson, bodyStr, resBodyStrLine, costTime);

        return resBodyStr;
    }

    /**
     * 发送POST请求，默认请求头：contentType=application/json;charset=UTF-8
     *
     * @param url      请求URL
     * @param bodyJson 请求body的json数据
     * @return
     * @throws Exception
     */
    public static JSONObject sendJsonPOST(String url, JSONObject bodyJson) {
        JSONObject headerJson = new JSONObject();
        headerJson.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);

        String resBodyStr = sendPOST(url, headerJson, null, bodyJson.toString());

        return new JSONObject(resBodyStr);
    }

    /**
     * 发送POST请求，默认请求头：contentType=application/json;charset=UTF-8
     *
     * @param url       请求URL
     * @param queryJson 请求的query参数的json数据
     * @param bodyJson  请求body的json数据
     * @return
     * @throws Exception
     */
    public static JSONObject sendJsonPOST(String url, JSONObject queryJson, JSONObject bodyJson) {
        JSONObject headerJson = new JSONObject();
        headerJson.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);

        String resBodyStr = sendPOST(url, headerJson, queryJson, bodyJson.toString());

        return new JSONObject(resBodyStr);
    }

    /**
     * 发送POST请求，默认请求头：contentType=application/json;charset=UTF-8
     *
     * @param url        请求URL
     * @param headerJson 请求头的Json数据
     * @param queryJson  请求的query参数的json数据
     * @param bodyJson   请求body的json数据
     * @return
     */
    public static JSONObject sendJsonPOST(String url, JSONObject headerJson, JSONObject queryJson, JSONObject bodyJson) {
        headerJson.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);

        String resBodyStr = sendPOST(url, headerJson, queryJson, bodyJson.toString());

        return new JSONObject(resBodyStr);
    }

    /**
     * 发送POST请求，默认请求头：contentType=text/xml
     *
     * @param url     请求URL
     * @param BodyXML 请求body的xml数据
     * @return 返回xml文本的Document对象
     * @throws Exception
     */
    public static Document sendXmlPOST(String url, Document BodyXML) throws Exception {
        JSONObject headerJson = new JSONObject();
        headerJson.put(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_XML_VALUE);

        String resBodyStr = sendPOST(url, headerJson, null, BodyXML.getRootElement().asXML());

        return DocumentHelper.parseText(resBodyStr);
    }

    /**
     * 发送GET请求
     *
     * @param url        请求URL
     * @param headerJson 请求头json数据
     * @param queryJson  请求参数query的json数据
     * @param recordRes  是否打印记录响应数据，转换为字符串
     * @return 响应body的byte数组
     * @throws Exception
     */
    public static byte[] sendGET(String url, JSONObject headerJson, JSONObject queryJson, boolean recordRes) {
        long start = System.currentTimeMillis();

        client.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

        if (queryJson != null) {
            url = url.contains("?") ? url : url + "?";

            StringBuilder urlBuffer = new StringBuilder(url);
            Set<String> querySet = queryJson.keySet();
            for (String queryName : querySet) {
                urlBuffer.append("&").append(queryName).append("=").append(queryJson.get(queryName).toString());
            }

            url = urlBuffer.toString();
        }

        HttpEntity<String> request = null;
        if (headerJson != null) {
            HttpHeaders headers = new HttpHeaders();
            Set<String> headerSet = headerJson.keySet();
            for (String headerName : headerSet) {
                headers.set(headerName, headerJson.getString(headerName));
            }

            request = new HttpEntity<>(null, headers);
        }

        ResponseEntity<byte[]> responseEntity = client.exchange(url, HttpMethod.GET, request, byte[].class);
        byte[] resBody = responseEntity.getBody();
        resBody = resBody == null ? new byte[]{} : resBody;

        String resBodyStr = recordRes ? new String(resBody, StandardCharsets.UTF_8) : "{}";

        long costTime = System.currentTimeMillis() - start;

        logger.info("[MyHttpUtil] - <sendGET> --- URL：{}，HEADER-JSON：{}，RESPONSE-BODY：{}，COST-TIME：{}ms", url, headerJson, resBodyStr, costTime);

        return resBody;
    }

    /**
     * 发送GET请求， 响应为json数据。
     *
     * @param url       请求URL
     * @param queryJson 请求参数的json数据
     * @return 返回Json对象
     * @throws Exception
     */
    public static JSONObject sendJsonGET(String url, JSONObject queryJson) throws Exception {
        byte[] resBody = sendGET(url, null, queryJson, true);
        String resBodyStr = new String(resBody, StandardCharsets.UTF_8);
        return new JSONObject(resBodyStr);
    }

    /**
     * 发送GET请求， 响应为json数据。
     *
     * @param url        请求URL
     * @param headerJson 请求头的json数据
     * @param queryJson  请求参数的json数据
     * @return 返回Json对象
     * @throws Exception
     */
    public static JSONObject sendJsonGET(String url, JSONObject headerJson, JSONObject queryJson) throws Exception {
        byte[] resBody = sendGET(url, headerJson, queryJson, true);
        String resBodyStr = new String(resBody, StandardCharsets.UTF_8);
        return new JSONObject(resBodyStr);
    }

    /**
     * 发送GET请求，响应为json数据。
     *
     * @param url 请求URL
     * @return 返回Json对象
     * @throws Exception
     */
    public static JSONObject sendJsonGET(String url) throws Exception {
        byte[] resBody = sendGET(url, null, null, true);
        String resBodyStr = new String(resBody, StandardCharsets.UTF_8);
        return new JSONObject(resBodyStr);
    }

    /**
     * 发送GET请求获取静态文件，并保存到指定目录下
     *
     * @param url  请求路径
     * @param path 保存文件的目录
     * @param name 文件名（根据响应内容自动添加文件后缀）
     * @return 成功：{"errCode":0,"path":"文件保存目录","name":"文件名","size":"文件字节大小","type":"文件类型"}，失败：{"errCode":-1}
     * @throws Exception
     */
    public static JSONObject getFile(String url, String path, String name) throws Exception {
        long start = System.currentTimeMillis();

        ResponseEntity<byte[]> responseEntity = client.getForEntity(url, byte[].class);

        File resultFile;
        JSONObject res = new JSONObject();
        res.put("errCode", -1);
        if (responseEntity.getStatusCodeValue() == 200) {
            byte[] result = responseEntity.getBody();
            result = result == null ? new byte[]{} : result;

            path = path.endsWith("/") ? path : path + "/";
            String type = Objects.requireNonNull(responseEntity.getHeaders().getContentType()).getSubtype();
            name += "." + type;
            String fullFileName = path + name;

            File file = new File(path);
            if (!file.exists()) {
                if (file.mkdirs()) {
                    throw new Exception("创建指定文件夹失败");
                }
            }

            resultFile = new File(fullFileName);
            OutputStream outputStream = new FileOutputStream(resultFile);
            outputStream.write(result);
            outputStream.flush();
            outputStream.close();

            res.put("errCode", 0);
            res.put("path", path);
            res.put("name", name);
            res.put("size", result.length);
            res.put("type", responseEntity.getHeaders().getContentType().toString());
        }

        long constTime = System.currentTimeMillis() - start;

        logger.info("[MyHttpUtil] - <getFile> --- URL：{}，RESPONSE-BODY：{}，COST-TIME：{}ms", url, res.toString(), constTime);

        return res;
    }


    /**
     * 获取IP地址字符串
     *
     * @return
     * @throws Exception
     */
    public static String getIPAddress() throws Exception {
        return getLocalHostLANAddress().getHostAddress();
    }

    /**
     * 获取网络IP地址，没有则返回本机IP地址的InetAddress对象
     *
     * @return
     * @throws Exception
     */
    public static InetAddress getLocalHostLANAddress() throws Exception {
        try {
            InetAddress candidateAddress = null;
            // 遍历所有的网络接口
            for (Enumeration<?> ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // 在所有的接口下再遍历IP
                for (Enumeration<?> inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {// 排除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // 如果是site-local地址，就是它了
                            return inetAddr;
                        } else if (candidateAddress == null) {
                            // site-local类型的地址未被发现，先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress;
            }
            // 如果没有发现 non-loopback地址.只能用最次选的方案
            InetAddress jdkSuppliedAddress = InetAddress.getLocalHost();
            if (jdkSuppliedAddress == null) {
                throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null.");
            }

            return jdkSuppliedAddress;
        } catch (Exception e) {
            UnknownHostException unknownHostException = new UnknownHostException("Failed to determine LAN address: " + e);
            unknownHostException.initCause(e);
            throw unknownHostException;
        }
    }

}
